package com.magicalcoder.lowcode.apiopen;

import ch.qos.logback.core.pattern.DynamicConverter;
import com.magicalcoder.lowcode.anotation.column.MagicalColumn;
import com.magicalcoder.lowcode.apiopen.dto.McHttpCache;
import com.magicalcoder.lowcode.config.MagicalLowcodeApiConfig;
import com.magicalcoder.lowcode.config.MagicalUploadFilePathConfig;
import com.magicalcoder.lowcode.constant.MagicalLowcodeConstant;
import com.magicalcoder.lowcode.core.common.exception.BusinessException;
import com.magicalcoder.lowcode.core.common.file.FileHelper;
import com.magicalcoder.lowcode.core.serialize.KeyValuePair;
import com.magicalcoder.lowcode.core.serialize.ResponseMsg;
import com.magicalcoder.lowcode.core.utils.*;
import com.magicalcoder.lowcode.dynamic.dto.McTable;
import com.magicalcoder.lowcode.dynamic.schema.McDynamicTableFactory;
import com.magicalcoder.lowcode.dynamic.sql.McDynamicCreator;
import com.magicalcoder.lowcode.dynamic.util.McDynamicTranserUtil;
import com.magicalcoder.lowcode.service.apiopen.dto.McPageData;
import com.magicalcoder.lowcode.service.apiopen.dto.McQuery;
import com.magicalcoder.lowcode.service.apiopen.service.MagicalApiOpenService;
import com.magicalcoder.lowcode.service.apiopen.service.MagicalCoderJpaService;
import com.magicalcoder.lowcode.service.global.dto.MagicalGlobal;
import com.magicalcoder.lowcode.service.global.dto.MagicalGlobalProxy;
import com.magicalcoder.lowcode.service.global.service.MagicalGlobalService;
import com.magicalcoder.lowcode.service.mcproject.dto.*;
import com.magicalcoder.lowcode.service.mcproject.dto.auth.MagicalAuth;
import com.magicalcoder.lowcode.service.mcproject.dto.auth.MagicalTableAuth;
import com.magicalcoder.lowcode.service.mcproject.dto.base.MagicalDragData;
import com.magicalcoder.lowcode.service.mcproject.engine.MagicalApiEngine;
import com.magicalcoder.lowcode.service.mcproject.service.MagicalApiService;
import com.magicalcoder.lowcode.service.mcproject.service.MagicalComponentService;
import com.magicalcoder.lowcode.service.mcproject.service.MagicalDatabaseService;
import com.magicalcoder.lowcode.service.mcproject.service.MagicalPageService;
import com.magicalcoder.lowcode.service.user.dto.MagicalUserComponent;
import com.magicalcoder.lowcode.service.user.service.MagicalUserComponentService;
import com.magicalcoder.lowcode.service.user.util.MagicalUserUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;

@RestController
@RequestMapping(value = "magical_lowcode/openapi/")
public class MagicalOpenApiController  {

    @Value("${server.servlet.context-path:}")
    private String contextPath;

    private static final String JSON_UTF8 = "application/json;charset=UTF-8";
    @Resource
    private MagicalApiService magicalApiService;
    @Resource
    private MagicalApiEngine magicalApiEngine;
    @Resource
    private MagicalUserComponentService magicalUserComponentService;
    @Resource
    private RestTemplate magicalRestTemplate;
    @Resource
    private MagicalComponentService magicalComponentService;
    @Resource
    private MagicalDatabaseService magicalDatabaseService;
    //代理接口MD5加密算法
    @Resource
    private MagicalLowcodeApiConfig magicalLowcodeApiConfig;
    @Resource
    private MagicalGlobalService magicalGlobalService;

    @Resource
    private MagicalCoderJpaService magicalCoderJpaService;
    @Resource
    private McDynamicTableFactory mcDynamicTableFactory;

    //这块要是做大 还得建模 映射等
    @RequestMapping(value = "proxy", consumes = JSON_UTF8,method = RequestMethod.POST)
    public Object proxy(@RequestBody Map<String,Object> reqEntity, HttpServletRequest request) {
        String url = reqEntity.remove("__url").toString();
        String method = reqEntity.remove("__method").toString();
        String contentType = reqEntity.remove("__contentType").toString();
        List<MagicalGlobalProxy> userProxys = magicalGlobalService.proxyCache();
        boolean matchProxy = false;
        if(ListUtil.isNotBlank(userProxys)){
            for(MagicalGlobalProxy proxy:userProxys){
                if(url.startsWith(proxy.getLocation())){
                    if(StringUtil.isNotBlank(proxy.getServer())){
                        url = proxy.getServer() + url;//加上服务名
                        matchProxy = true;
                    }
                }
            }
        }
        if(!matchProxy && magicalLowcodeApiConfig.getProxy()!=null){
            Set<String> sets = magicalLowcodeApiConfig.getProxy().keySet();
            for(String prefix:sets){
                String server = magicalLowcodeApiConfig.getProxy().get(prefix);
                if(url.startsWith(prefix)){
                    url = server + url;//加上服务名
                }
            }
        }
        if(!url.startsWith("http")){
            throw new BusinessException(-1,"您的url未在magicalcoder.lowcode.api.proxy匹配到代理服务器,或者请把/前缀去掉再试试");
        }
        Map<String,Object> obj = new HashMap<>();
        if("get".equals(method)){
            //url
            StringBuilder urlSb = new StringBuilder(url);
            if(reqEntity!=null && !reqEntity.isEmpty()){
                StringBuilder params = new StringBuilder();
                for(String key : reqEntity.keySet()){
                    params.append("&").append(key).append("=").append("{"+key+"}");
                }
                if(url.contains("?")){
                    if(url.endsWith("?")){
                        urlSb.append(StringUtil.deleteBeforeChar(params.toString(),1));
                    }else {
                        urlSb.append(params.toString());
                    }
                }else {
                    urlSb.append("?").append(StringUtil.deleteBeforeChar(params.toString(),1));
                }
            }

            HttpHeaders headers = new HttpHeaders();
            addUserInfoToHeader(request,headers);
            HttpEntity httpEntity = new HttpEntity( headers);
            ResponseEntity<Object> exchange = magicalRestTemplate.exchange(urlSb.toString(), HttpMethod.GET, httpEntity, Object.class,reqEntity);
            Object res = exchange.getBody();
            if(res==null){
                return new ResponseMsg<>(null);
            }
            if(!(res instanceof Map)){
                return new ResponseMsg<>(res);
            }
            obj = (Map<String, Object>)exchange.getBody();
        }else {
            if(contentType.contains("application/json")){
                //默认用json
                HttpHeaders headers = new HttpHeaders();
                MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
                headers.setContentType(type);
                headers.add("Accept", MediaType.APPLICATION_JSON.toString());
                addUserInfoToHeader(request,headers);
                HttpEntity<String> formEntity = new HttpEntity<String>(GsonUtil.toJson(reqEntity), headers);
                String s = magicalRestTemplate.postForEntity(url,formEntity,String.class).getBody();
                if(s==null){
                    return new ResponseMsg<>(null);
                }
                if(!s.startsWith("{")){
                    if(s.startsWith("[")){
                        return new ResponseMsg<>(GsonUtil.toList(s,Object.class));
                    }
                    return new ResponseMsg<>(s);
                }
                obj = (Map<String, Object>) GsonUtil.toObj(s,Object.class);
            }else {//之前的默认都用这个方式请求
                HttpHeaders headers = new HttpHeaders();
                // 以表单的方式提交
                headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                //将请求头部和参数合成一个请求
                MultiValueMap<String, String>  query = new LinkedMultiValueMap();
                if(reqEntity!=null && !reqEntity.isEmpty()){//自动遍历get的入参
                    for(String key:reqEntity.keySet()){
                        query.add(key,reqEntity.get(key).toString());
                    }
                }
                addUserInfoToHeader(request,headers);
                HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity(query, headers);
                //执行HTTP请求，将返回的结构使用ResultVO类格式化
                ResponseEntity<String> response = magicalRestTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
                String s = response.getBody();
                if(s==null){
                    return new ResponseMsg<>(null);
                }
                if(!s.startsWith("{")){
                    if(s.startsWith("[")){
                        return new ResponseMsg<>(GsonUtil.toList(s,Object.class));
                    }
                    return new ResponseMsg<>(s);
                }
                obj = (Map<String, Object>) GsonUtil.toObj(response.getBody(),Object.class);
            }
        }

        if(obj.get("code")!=null && obj.get("code").toString().equals("0")||Double.valueOf(obj.get("code").toString())==0){
            if(obj.containsKey("data")){
                Map<String ,Object> extra = new HashMap<>();
                Set<String> keys = obj.keySet();
                for(String key:keys){
                    if(!",code,flag,data,desc,count,".contains(","+key+",")){
                        extra.put(key,obj.get(key));
                    }
                }
                ResponseMsg res = new ResponseMsg();
                res.setData(obj.get("data"));
                if(obj.get("count")!=null){
                    res.setCount(Double.valueOf(obj.get("count").toString()).intValue());
                }
                if(!extra.isEmpty()){
                    res.setExtra(extra);
                }
                return res;
            }
        }
        return obj;
    }
    private void addUserInfoToHeader(HttpServletRequest request,HttpHeaders headers){
        String webUserId = MagicalUserUtil.getWebUserId(request);
        if(StringUtil.isNotBlank(webUserId)){
            headers.add("webuid",webUserId);
        }

        String adminUserId = MagicalUserUtil.getAdminUserId(request);
        if(adminUserId!=null){
            headers.add("adminuid",adminUserId.toString());
        }
        //为了服务端接口安全，特提供简单MD5加密接口方法，避免接口被人乱调用
        String timeStemp = System.currentTimeMillis()+"";
        headers.add("time",timeStemp);
        String md5Password = magicalLowcodeApiConfig.getMd5Password();
        if(md5Password==null){
            md5Password="";
        }
        headers.add("sign",Md5Util.md5Encode(timeStemp+md5Password));
        //获取下cookie
        Cookie[] cookies = request.getCookies();
        if(cookies!=null){
            for(Cookie cookie:cookies){
                String name = cookie.getName();
                String value = cookie.getValue();
                if("__cookie".equals(name)){
                    try {
                        headers.add("Cookie", URLDecoder.decode(value,"UTF-8"));
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    @RequestMapping(value = "get/{uuid}")
    public ResponseMsg getData(@PathVariable String uuid,HttpServletRequest request) {
        Map<String,Object> query = new HashMap<>();
        if(query==null){
            query = new HashMap<>();
        }
        Map<String,String[]> reqMap = request.getParameterMap();
        if(!reqMap.isEmpty()){//自动遍历get的入参
            for(String key:reqMap.keySet()){
                query.put(key,reqMap.get(key)[0]);
            }
        }
        MagicalApi api = magicalApiService.apiSlowGet(uuid);
        checkApiAuth(request,api.getAuth());
        query.put("$webUserId",MagicalUserUtil.getWebUserId(request));
        query.put("$adminUserId",MagicalUserUtil.getAdminUserId(request));
        return new ResponseMsg(magicalApiEngine.execute(api,query));
    }

    //同时支持get post 统一更简单 全面支持客户端的数据接收
    @RequestMapping(value = "post/{uuid}", consumes = JSON_UTF8)
    public ResponseMsg postData(@PathVariable String uuid,
                                @RequestBody Map<String, Object> query, HttpServletRequest request) {
        if(query==null){
            query = new HashMap<>();
        }
        Map<String,String[]> reqMap = request.getParameterMap();
        if(reqMap!=null && !reqMap.isEmpty()){//自动遍历get的入参
            for(String key:reqMap.keySet()){
                query.put(key,reqMap.get(key)[0]);
            }
        }
        MagicalApi api = magicalApiService.apiSlowGet(uuid);
        checkApiAuth(request,api.getAuth());
        query.put("$webUserId",MagicalUserUtil.getWebUserId(request));
        query.put("$adminUserId",MagicalUserUtil.getAdminUserId(request));
        return new ResponseMsg(magicalApiEngine.execute(api,query));
    }

    @Resource
    private MagicalApiOpenService magicalApiOpenService;


    @Resource
    private EntityManager entityManager;
    private void checkApiAuth(HttpServletRequest request, MagicalAuth auth){
        if(MagicalUserUtil.getUser(request)!=null){//开发者放过校验
            return;
        }
        //网站用户 仔细校验
        String webLoginUid = MagicalUserUtil.getWebUserId(request);
        //管理员
        Long adminLoginUid = (Long) request.getAttribute(MagicalLowcodeConstant.adminLoginUid);
        if (adminLoginUid!=null){//后台管理员就放过登录校验
            return;
        }
        if(auth==null){
            return;
        }
        if(StringUtil.isNotBlank(webLoginUid)){
            if(!auth.isUserLogin()){
                throw new BusinessException(-1,"暂无权限");
            }
        }else {
            if(!auth.isAnonymous() && auth.isUserLogin()){
                throw new BusinessException(-20,"请先登录");
            }
            if(!auth.isAnonymous()){
                throw new BusinessException(-1,"暂无权限");
            }
        }
    }

    /*根据主键获取 url带参数 不适合低代码 换用getByPk*/
    @Deprecated
    @RequestMapping(value = "crud/{tableName}/find-by-pk/{id}")
    public ResponseMsg findById(HttpServletRequest request,@RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName, @PathVariable String id){
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.findByPk);
        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                Map<String,Object> entity = creator.findById(table,id);
                return new ResponseMsg(entity);
            }
        }
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        Object obj = entityManager.find(clazz,magicalApiOpenService.translateId(clazz,id));
        checkWebUidAuth(request,clazz,obj);
        return new ResponseMsg(obj);
    }
    /*根据主键获取*/
    @RequestMapping(value = "crud/{tableName}/get-by-pk")
    public ResponseMsg getById(HttpServletRequest request,@RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName,
                               @RequestParam String id){
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.getByPk);
        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                Map<String,Object> entity = creator.findById(table,id);
                return new ResponseMsg(entity);
            }
        }
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        Object obj = entityManager.find(clazz,magicalApiOpenService.translateId(clazz,id));
        checkWebUidAuth(request,clazz,obj);
        return new ResponseMsg(obj);
    }

    @RequestMapping(value = "crud/{tableName}/delete-by-pk",consumes = JSON_UTF8,method = RequestMethod.POST)
    public ResponseMsg delete(HttpServletRequest request,@RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName,@RequestBody Map<String,Object> req){
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.deleteByPk);

        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                Map<String,Object> _info = MapUtil.buildMap("catalog",catalog,"schema",schema,"table",tableName);
                req.put("_info",_info);
                creator.removeParentChildren(req);
                return new ResponseMsg();
            }
        }


        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        //shanc
        String webUidFieldName = webUidFieldName(clazz);
        if(StringUtil.isNotBlank(webUidFieldName)){
            String pkName = pkName(clazz);
            if(pkName!=null){
                Object id = req.get(pkName);
                Object existObj = entityManager.find(clazz,magicalApiOpenService.translateId(clazz,id.toString()));
                checkWebUidAuth(request,clazz,existObj);
            }
        }
        Map<String,Object> _info = MapUtil.buildMap("catalog",catalog,"schema",schema,"table",tableName);
        req.put("_info",_info);
        magicalApiOpenService.removeParentChildren(req);
        return new ResponseMsg();
    }

    @RequestMapping(value = "crud/{tableName}/insert",consumes = JSON_UTF8,method = RequestMethod.POST)
    public ResponseMsg persist(HttpServletRequest request,@RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName, @RequestBody Map<String,Object> req) {
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.insert);

        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                Object id = creator.insert(table,req);
                return new ResponseMsg(id);
            }
        }


        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        autoSetValueFromMagicalColumn(request,req,clazz);
        String json = GsonUtil.toJson(req);
        Object obj = GsonUtil.toObj(json,clazz);
        magicalApiOpenService.persist(obj);
        return new ResponseMsg(magicalApiOpenService.pkValue(obj));
    }
    //如果主键不传 会默认insert 否则 update 不传的字段就忽略更新 这样更加灵活 不需要整表被全部更新
    @RequestMapping(value = "crud/{tableName}/save",consumes = JSON_UTF8,method = RequestMethod.POST)
    public ResponseMsg merge(HttpServletRequest request,@RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName, @RequestBody Map<String,Object> req) {
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.save);
        Map<String,Object> result = saveTable(catalog,schema,tableName,req);
        return new ResponseMsg(result.get("id"));
    }

    private Map<String, Object> saveTable(String catalog,String schema,String tableName,Map<String, Object> req) {
        Set<String> keys = req.keySet();
        Map<String,Map<String,Object>> tableMap = new HashMap<>();
        //SaveList DeleteList
        for(String key:keys){
            if(key.startsWith("_")&&key.endsWith("_info")){
                String _tableName = key.substring(0,key.length()-5);
                List<Map<String,Object>> saveList= (List<Map<String,Object>>)req.get(_tableName+"_save_list");
                List<Map<String,Object>> deleteList= (List<Map<String,Object>>)req.get(_tableName+"_delete_list");
                Map<String,Object> _info = (Map<String,Object>)req.get(_tableName+"_info");

                Map<String,Object> saveDeleteMap = tableMap.get(_tableName);
                if(saveDeleteMap==null){
                    tableMap.put(_tableName,new HashMap<>());
                }
                tableMap.get(_tableName).put("saveList",saveList);
                tableMap.get(_tableName).put("deleteList",deleteList);
                tableMap.get(_tableName).put("_info",_info);
            }
        }
        List<Map<String,Object>> _children = new ArrayList<>();
        Set<String> tableKeys = tableMap.keySet();
        for(String key:tableKeys){
            _children.add(tableMap.get(key));
        }

        Map<String,String> _info = new HashMap<>();
        _info.put("catalog",catalog);
        _info.put("schema",schema);
        _info.put("table",tableName);
        req.put("_info",_info);
        req.put("_children",_children);
        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                return creator.saveParentChildren(req);
            }
        }
        return magicalApiOpenService.saveParentChildren(req);
    }

    //更新不包含null属性
    @RequestMapping(value = "crud/{tableName}/update",consumes = JSON_UTF8,method = RequestMethod.POST)
    public ResponseMsg update(HttpServletRequest request,@RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName, @RequestBody Map<String,Object> req) {
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.save);

        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                //如果null属性值 则忽略
                McDynamicTranserUtil.removeKeyWhileNullValue(req,false);
                creator.updateById(table,req);
                return new ResponseMsg(creator.getPkValue(table,req));
            }
        }

        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        autoSetValueFromMagicalColumn(request,req,clazz);
        String json = GsonUtil.toJson(req);
        Object obj = GsonUtil.toObj(json,clazz);
        //从库里查出来实体
        Object dbEntity = magicalApiOpenService.get(obj);
        //合并实体
        CopyUtil.copyIgnoreNull(obj,dbEntity);
        //持久化
        Object newEntity = magicalApiOpenService.merge(dbEntity);
        return new ResponseMsg(magicalApiOpenService.pkValue(newEntity));
    }
    @RequestMapping(value = "crud/{tableName}/first",consumes = JSON_UTF8,method = RequestMethod.POST)
    public ResponseMsg first(HttpServletRequest request,@RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName,
                             @RequestParam(required = false) Integer page,@RequestParam(required = false) Integer limit,
                             @RequestBody Map<String,Object> req) {
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.first);
        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                //如果null属性值 则忽略
                McQuery mcQuery = McDynamicTranserUtil.toMcQuery(table,req,page,1);
                List list = creator.queryList(table,mcQuery);
                if(ListUtil.isNotBlank(list)){
                    return new ResponseMsg(list.get(0));
                }else {
                    return new ResponseMsg();
                }
            }
        }
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        List list = magicalApiOpenService.queryList(clazz,toMcQuery(request,clazz,req,page,limit));
        if(ListUtil.isNotBlank(list)){
            return new ResponseMsg(list.get(0));
        }else {
            return new ResponseMsg();
        }
    }
    //mcStart mcLimit 是分页参数 {"param":{"createTime":"2021-05-08 11:47:55"},"condition":{"createTime":">"}}
    @RequestMapping(value = "crud/{tableName}/list",consumes = JSON_UTF8,method = RequestMethod.POST)
    public ResponseMsg list(HttpServletRequest request,@RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName,
                            @RequestParam(required = false) Integer page,@RequestParam(required = false) Integer limit,
                            @RequestBody Map<String,Object> req) {
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.list);
        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                //如果null属性值 则忽略
                McQuery mcQuery = McDynamicTranserUtil.toMcQuery(table,req,page,limit);
                List list = creator.queryList(table,mcQuery);
                return new ResponseMsg(list);
            }
        }
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        List list = magicalApiOpenService.queryList(clazz,toMcQuery(request,clazz,req,page,limit));
        return new ResponseMsg(list);
    }
    //仅支持登陆后的用户查询自己的数据
    @RequestMapping(value = "crud/{tableName}/my-list",consumes = JSON_UTF8,method = RequestMethod.POST)
    public ResponseMsg myList(HttpServletRequest request,@RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName,
                            @RequestParam(required = false) Integer page,@RequestParam(required = false) Integer limit,
                            @RequestBody Map<String,Object> req) {
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.myList);
        String webLoginUid = MagicalUserUtil.getWebUserId(request);
        if(StringUtil.isBlank(webLoginUid)){
            return new ResponseMsg();
        }
        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                //如果null属性值 则忽略
                McQuery mcQuery = McDynamicTranserUtil.toMcQuery(table,req,page,limit);
                List list = creator.queryList(table,mcQuery);
                return new ResponseMsg(list);
            }
        }
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        String webUidFieldName = webUidFieldName(clazz);
        if(StringUtil.isBlank(webUidFieldName)){//
            return new ResponseMsg();
        }
        List list = magicalApiOpenService.queryList(clazz,toMcQuery(request,clazz,req,page,limit));
        return new ResponseMsg(list);
    }
    //mcStart mcLimit 是分页参数

    /**
     * {"param":{"createTime":"2021-05-08 11:47:55"},"condition":{"createTime":">"}}
     * @param catalog
     * @param schema
     * @param tableName
     * @param req
     * @return
     */
    @RequestMapping(value = "crud/{tableName}/page",consumes = JSON_UTF8,method = RequestMethod.POST)
    public ResponseMsg page(HttpServletRequest request,
        @RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName,
        @RequestParam(required = false) Integer page,@RequestParam(required = false) Integer limit,
        @RequestBody Map<String,Object> req) {
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.page);
        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                //如果null属性值 则忽略
                McQuery mcQuery = McDynamicTranserUtil.toMcQuery(table,req,page,limit);
                McPageData mcPageData = creator.queryPageData(table,mcQuery);
                ResponseMsg result = new ResponseMsg();
                result.setCount(mcPageData.getCount());
                result.setData(mcPageData.getData());
                return result;
            }
        }

        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        McPageData mcPageData = magicalApiOpenService.queryPageData(clazz,toMcQuery(request,clazz,req,page,limit));
        ResponseMsg result = new ResponseMsg();
        result.setCount(mcPageData.getCount());
        result.setData(mcPageData.getData());
        return result;
    }
    //导出
    @RequestMapping(value = "crud/{tableName}/export-excel",consumes = JSON_UTF8,method = RequestMethod.POST)
    public void exportExcel(HttpServletRequest request,HttpServletResponse response,
                            @RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName,
                            @RequestParam(required = false) Integer page,@RequestParam(required = false) Integer limit,
                            @RequestBody Map<String,Object> req) throws Exception {
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.exportExcel);
        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                //如果null属性值 则忽略
                McQuery mcQuery = McDynamicTranserUtil.toMcQuery(table,req,page,limit);
                McPageData mcPageData = creator.queryPageData(table,mcQuery);
                ExcelUtil.writeListToExcel(response,mcPageData.getData(),table);
                return;
            }
        }

        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        McPageData mcPageData = magicalApiOpenService.queryPageData(clazz,toMcQuery(request,clazz,req,page,limit));
        List<Object> list = mcPageData.getData();
        ExcelUtil.writeListToExcel(response,list,clazz);
    }



    @RequestMapping(value = "crud/{tableName}/import-excel",method = RequestMethod.POST)
    public ResponseMsg importExcel(HttpServletRequest request,
                            @RequestParam MultipartFile[] file,
                            @RequestParam(required = false) String catalog,@RequestParam(required = false) String schema,@PathVariable String tableName
                            ){
        checkTableAuth(request,tableName, MagicalLowcodeConstant.AuthMethodType.importExcel);
        McDynamicCreator creator = mcDynamicTableFactory.getDynamicCreator();
        if(creator!=null){
            McTable table = creator.getMcTable(catalog, schema, tableName);
            if(table!=null){
                //如果null属性值 则忽略
                List list = ExcelUtil.readExcelList(file[0],table);
                creator.batchSave(table,list);
                return new ResponseMsg();
            }
        }
        Class clazz = magicalApiOpenService.scannerClass(catalog,schema,tableName);
        List list = ExcelUtil.readExcelList(file[0],clazz);
        magicalApiOpenService.batchSave(list);
        return new ResponseMsg();
    }
    private void checkTableAuth(HttpServletRequest request, String tableName, MagicalLowcodeConstant.AuthMethodType method){
        if(MagicalUserUtil.getUser(request)!=null){//开发者放过校验
            return;
        }
        //网站用户 仔细校验
        String webLoginUid = MagicalUserUtil.getWebUserId(request);
        //管理员
        Object adminLoginUid = request.getAttribute(MagicalLowcodeConstant.adminLoginUid);
        if (adminLoginUid!=null){//后台管理员就放过登录校验
            return;
        }

        String projectUuid = request.getHeader("pid");
        if(StringUtil.isBlank(projectUuid) || "null".equals(projectUuid)){
            throw new BusinessException(-2,"服务端发生变更,您可以尝试重新登录");
        }
        List<MagicalDatabase> databases = magicalDatabaseService.databases(projectUuid);
        if(!hasPermit(databases,tableName,method,webLoginUid)){
            throw new BusinessException(-1,"暂无权限");
        }
    }

    private boolean hasPermit(List<MagicalDatabase> databases,String tableName, MagicalLowcodeConstant.AuthMethodType method,String webLoginUid){
        for(MagicalDatabase database:databases){
            List<MagicalTable> tables = database.getChildren();
            for(MagicalTable table:tables){
                if(!table.getName().equals(tableName)){
                    continue;
                }
                MagicalTableAuth auth = table.getAuth();
                if(auth!=null){
                    if(StringUtil.isNotBlank(webLoginUid)){
                        switch (method){
                            case getByPk:return auth.getGetByPk().isUserLogin();
                            case insert:return auth.getInsert().isUserLogin();
                            case deleteByPk:return auth.getDeleteByPk().isUserLogin();
                            case save:return auth.getSave().isUserLogin();
                            case list:return auth.getList().isUserLogin();
                            case page:return auth.getPage().isUserLogin();
                            case first:return auth.getFirst().isUserLogin();
                            case myList:return auth.getMyList().isUserLogin();
                            case importExcel:return auth.getImportExcel().isUserLogin();
                            case exportExcel:return auth.getExportExcel().isUserLogin();
                        }
                    }else {//匿名用户
                        switch (method){
                            case getByPk:
                                if(!auth.getGetByPk().isAnonymous() && auth.getGetByPk().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getGetByPk().isAnonymous();
                            case insert:
                                if(!auth.getInsert().isAnonymous() && auth.getInsert().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getInsert().isAnonymous();
                            case deleteByPk:
                                if(!auth.getDeleteByPk().isAnonymous() && auth.getDeleteByPk().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getDeleteByPk().isAnonymous();
                            case save:
                                if(!auth.getSave().isAnonymous() && auth.getSave().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getSave().isAnonymous();
                            case list:
                                if(!auth.getList().isAnonymous() && auth.getList().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getList().isAnonymous();
                            case page:
                                if(!auth.getPage().isAnonymous() && auth.getPage().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getPage().isAnonymous();
                            case first:
                                if(!auth.getFirst().isAnonymous() && auth.getFirst().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getFirst().isAnonymous();
                            case myList:
                                if(!auth.getMyList().isAnonymous() && auth.getMyList().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getMyList().isAnonymous();
                            case importExcel:
                                if(!auth.getImportExcel().isAnonymous() && auth.getImportExcel().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getImportExcel().isAnonymous();
                            case exportExcel:
                                if(!auth.getExportExcel().isAnonymous() && auth.getExportExcel().isUserLogin()){
                                    throw new BusinessException(-20,"请先登录");
                                }
                                return auth.getExportExcel().isAnonymous();
                        }
                    }
                }
            }
        }
        return true;
    }
    private void autoSetValueFromMagicalColumn(HttpServletRequest request, Map<String,Object> req, Class clazz){

        Map<String,MagicalColumn> columnMap = new HashMap<>();
        String pkName = null;
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();//字段名
            MagicalColumn magicalColumn = field.getAnnotation(MagicalColumn.class);
            if(magicalColumn!=null){
                columnMap.put(name,magicalColumn);
            }
            if(field.getAnnotation(Id.class)!=null){
                pkName = name;
            }
        }
        if(columnMap.isEmpty()){
            return;//未配置登录用户ID
        }
        Object pkParamValue = req.get(pkName);//获取ID
        if(pkParamValue!=null){//跟库里对比 防止篡改别人数据
            String webUserId = MagicalUserUtil.getWebUserId(request);
            if(StringUtil.isNotBlank(webUserId)){
                Object existObj = entityManager.find(clazz,magicalApiOpenService.translateId(clazz,pkParamValue.toString()));
                checkWebUidAuth(request,clazz,existObj);
            }
        }

        if(columnMap!=null && !columnMap.isEmpty()){
            for(String field:columnMap.keySet()){
                Object value = req.get(field);
                MagicalColumn column = columnMap.get(field);
                if(column.webUserId()){
                    req.put(field,MagicalUserUtil.getWebUserId(request));
                }
                if(value!=null){
                    //MD5
                    if(StringUtil.isNotBlank(value.toString())){
                        String md5Password = column.md5Password();
                        if(StringUtil.isNotBlank(md5Password)){
                            if(value.toString().length()!=32){//md5长度是32位
                                String newMd5 = Md5Util.md5Encode(value.toString()+md5Password);
                                req.put(field,newMd5);
                            }
                        }
                    }

                }

            }
        }

    }
    private String webUidFieldName(Class clazz){
        Map<String,MagicalColumn> columnMap = magicalColumnMap(clazz);
        if(columnMap!=null && !columnMap.isEmpty()){
            for(String field:columnMap.keySet()){
                MagicalColumn column = columnMap.get(field);
                if(column.webUserId()){//需要被控制
                    return field;
                }
            }
        }
        return null;
    }

    //获取主键名称
    private String pkName(Class clazz){
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f:declaredFields){
            String name = f.getName();
            Id id = f.getAnnotation(Id.class);
            if(id!=null){
                return name;
            }
        }
        return null;
    }
    private void checkWebUidAuth(HttpServletRequest request,Class clazz,Object obj){
        if(obj == null){
            return ;
        }
        String webUid = MagicalUserUtil.getWebUserId(request);
        if(StringUtil.isNotBlank(webUid)){
            String webUidFieldName = webUidFieldName(clazz);
            if(StringUtil.isNotBlank(webUidFieldName)){
                ReflectUtil<String,Object> reflectUtil = new ReflectUtil();
                String dbWebUid = reflectUtil.getBeanValue(obj,webUidFieldName);
                if(!webUid.equals(dbWebUid)){
                    throw new BusinessException(-1,"此条数据不属于您");
                }
            }
        }
    }



    private Map<String,MagicalColumn> magicalColumnMap(Class clazz){
        Map<String, MagicalColumn> columnMap = new HashMap<>();
        //in条件如何处理
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();//字段名
            MagicalColumn magicalColumn = field.getAnnotation(MagicalColumn.class);
            if(magicalColumn!=null){
                columnMap.put(name,magicalColumn);
            }
        }
        return columnMap;
    }

    private McQuery toMcQuery(HttpServletRequest request,Class clazz,Map<String,Object> req,Integer page,Integer limit) {
        return magicalApiOpenService.toMcQuery(request, clazz, req, page, limit);
    }

        @Resource
        private MagicalUploadFilePathConfig magicalUploadFilePathConfig;


        /**
         * @param file       上传的新文件流
         * @param originFile 原始文件路径
         * @param from       来源是否是富文本kindeditor  可以自行处理返回给富文本的值
         * @return
         * @throws IOException
         * 废弃了 不建议使用 因为存储的图片混在一起 没法区分项目ID
         */
/*
        @Deprecated
        @RequestMapping(value = "upload", method = RequestMethod.POST)
        public Object fileUpload(@RequestParam MultipartFile[] file,
            @RequestParam(required = false, value = "originFile") String originFile,
            @RequestParam(required = false, value = "from") String from,
            HttpServletRequest request, HttpServletResponse response)
        throws IOException {
            if(!magicalUploadFilePathConfig.getUseDisk()){
                throw new BusinessException("文件上传功能已关闭");
            }
            String originFilePath = magicalUploadFilePathConfig.originFilePath(originFile);
            String realPath = magicalUploadFilePathConfig.getUploadDiskFolder() + originFilePath;
            //如果文件夹不存在就新建一个文件夹 聪明的根据当前目录规则来进行上传
            File dirPath = new File(realPath);
            if (!dirPath.exists()) {
                dirPath.mkdirs();
            }
            String originalFilename = null;
            List<Map> returnUrls = new ArrayList<>();
            for (MultipartFile myfile : file) {
                if (!myfile.isEmpty()) {
                    // 获取文件名
                    originalFilename = myfile.getOriginalFilename();
                    String returnUrl = "";
                    File storeFile = null;
                    // 文件名后缀处理 使用uuid方式生成新文件名称 绝对唯一
                    String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
                    String newFileName = UUID.randomUUID().toString() + suffix;
                    if (magicalUploadFilePathConfig.getUseDisk()) {//本地路径
                        storeFile = new File(realPath, newFileName);
                        if (!storeFile.getParentFile().exists()) {
                            storeFile.getParentFile().mkdirs();
                        }
                        Files.copy(myfile.getInputStream(), storeFile.toPath());
                        String prefix = magicalUploadFilePathConfig.getFileExtraAddPrefix() + originFilePath;
                        String src = prefix + newFileName;
                        while (src.contains("//")) {
                            src = src.replace("//", "/");
                        }
                        if (magicalUploadFilePathConfig.getUseDiskReturnUrl()) {
                            returnUrl = src;
                        }
                    }

                    String miniType = URLConnection.guessContentTypeFromName(originalFilename);

                    returnUrls.add(MapUtil.buildMap("url", returnUrl, "name", originalFilename,"miniType",miniType,"size",myfile.getSize(),"sizeFormat", FileHelper.getFileSize(myfile.getSize()),"newFileName",newFileName,"suffix",suffix));
                }
            }
            if (ListUtil.isNotBlank(returnUrls)) {
                if (returnUrls.size() == 1) {//单个文件上传 返回1个地址
                    if("kindeditor".equals(from)){
                        String prefix = contextPath;
                        if(!contextPath.endsWith("/")){
                            prefix = prefix+"/";
                        }
                        return MapUtil.buildMap("error",0,"url",prefix+returnUrls.get(0).get("url"));
                    }
                    return new ResponseMsg(returnUrls.get(0));
                }
                //多个文件 返回多个地址
                return new ResponseMsg(returnUrls);
            }
            throw new BusinessException(new KeyValuePair(-1, "文件不存在", "文件不存在"));
        }
*/

        @Resource
        private MagicalPageService magicalPageService;
        //这个对外的publish.html 别锁了
        @GetMapping("page/editor")
        public ResponseMsg getPageEditor(@RequestParam String projectUuid,@RequestParam String uuid){
            MagicalPage magicalPage = magicalPageService.pageInfo(projectUuid,uuid);
            MagicalDragData result = new MagicalDragData();
            CopyUtil.copy(magicalPage.getData(),result,"screenShot");
            result.setName(magicalPage.getName());//作为标题
            return new ResponseMsg(result);
        }
        //处理用户自定义的组件js 要缓存一下效果更好
        @GetMapping("/page/ui/user-components.js")
        public void pageUiJs(@RequestParam String projectUuid,HttpServletRequest request,HttpServletResponse response) throws IOException {
            List<MagicalComponent> components = magicalComponentService.localComponents(projectUuid);
            StringBuilder js = new StringBuilder();
            if(ListUtil.isNotBlank(components)){
                for(MagicalComponent component:components){
                    if(component.getOrder()<0){
                        continue;
                    }
                    if(StringUtil.isNotBlank(component.getUiJs())){
                        js.append("var _______t=1;");
                        js.append("try{\n");
                        js.append(component.getUiJs()).append(";\n");
                        js.append("}catch(e){console.log(e)}\n");
                    }
                }
            }
            toStream(request,response,"application/javascript",js.toString());
        }
        private Map<String, McHttpCache> httpCacheMap = new HashMap<>();

        @GetMapping("/page/iframe/user-constant.js")
        public void pageIframeConstant(@RequestParam(required = false) String projectUuid,
                                       @RequestParam(required = false) String pageUuid,
                                       HttpServletRequest request,
                                       HttpServletResponse response) throws IOException {
            List<MagicalGlobalProxy> proxies = magicalGlobalService.proxyCache();
            StringBuilder js = new StringBuilder();
            js.append("if(!window.MC){window.MC = {};}\ntry{\n");
            js.append("window.MC.CONSTANT={global:{proxy:null}};");
            Map<String,String> oldProxy = magicalLowcodeApiConfig.getProxy();
            if(proxies==null){
                proxies = new ArrayList<>();
            }
            Map<String,MagicalGlobalProxy> existMaps = MapUtil.listToItemMap("location",proxies);
            //yml的rocket-api代理兼容一下
            if(oldProxy!=null){
                for(String key:oldProxy.keySet()){
                    if(existMaps.containsKey(key)){
                        continue;//以用户配置优先
                    }
                    String server = oldProxy.get(key);
                    MagicalGlobalProxy proxy = new MagicalGlobalProxy();
                    proxy.setLocation(key);
                    proxy.setServer(server);
                    proxies.add(proxy);
                }
            }

//            if(ListUtil.isNotBlank(proxies)){
                js.append(String.format("window.MC.CONSTANT.global.proxy=%s;",GsonUtil.toJson(proxies)));
//            }
            //查找页面需要加载的资源文件

            if(StringUtil.isNotBlank(pageUuid)){
                MagicalPage magicalPage = magicalPageService.pageInfo(projectUuid,pageUuid);
                if(magicalPage!=null && magicalPage.getOpenImport()!=null && magicalPage.getOpenImport()){//主动开启才有用
                    String imports = magicalPage.getData().getImports();
                    if(StringUtil.isNotBlank(imports)){
                        js.append(String.format("window.MC.CONSTANT.sysImports=%s;",imports));//系统引入的资源
                    }
                    if(StringUtil.isNotBlank(magicalPage.getImports())){
                        js.append(String.format("window.MC.CONSTANT.imports=%s;",magicalPage.getImports()));
                    }
                }
            }
            js.append("}catch(e){console.log(e)}");
            toStream(request,response,"application/javascript",js.toString());
        }
        @GetMapping("/page/iframe/user-components.js")
        public void pageIframeJs(@RequestParam String projectUuid, HttpServletRequest request,HttpServletResponse response) throws IOException {
            List<MagicalComponent> components = magicalComponentService.localComponents(projectUuid);
            StringBuilder js = new StringBuilder();
            if(ListUtil.isNotBlank(components)){
                for(MagicalComponent component:components){
                    if(component.getOrder()<0){
                        continue;
                    }
                    if(StringUtil.isNotBlank(component.getIframeJs())){
                        js.append("try{\n");
                        js.append(component.getIframeJs()).append("\n");
                        js.append("}catch(e){console.log(e)}\n");
                    }
                }
            }
            toStream(request,response,"application/javascript",js.toString());
        }
        @GetMapping("/page/iframe/user-components.css")
        public void pageIframeCss(@RequestParam String projectUuid,HttpServletRequest request,HttpServletResponse response) throws IOException {
            List<MagicalComponent> components = magicalComponentService.localComponents(projectUuid);
            StringBuilder css = new StringBuilder();
            if(ListUtil.isNotBlank(components)){
                for(MagicalComponent component:components){
                    if(component.getOrder()<0){
                        continue;
                    }
                    if(StringUtil.isNotBlank(component.getIframeCss())){
                        css.append(component.getIframeCss()).append("\n");
                    }
                }
            }
            toStream(request,response,"text/css",css.toString());
        }



        @Deprecated
        //处理用户自定义的组件js 要缓存一下效果更好
        @GetMapping("/ui/user-components.js")
        public void uiJs(HttpServletRequest request,HttpServletResponse response) throws IOException {
            List<MagicalUserComponent> components = magicalUserComponentService.allDistinctComponents();
            StringBuilder js = new StringBuilder();
            if(ListUtil.isNotBlank(components)){
                for(MagicalUserComponent component:components){
                    if(StringUtil.isNotBlank(component.getUiJs())){
                        js.append("var _______t=1;");
                        js.append("try{\n");
                        js.append(component.getUiJs()).append(";\n");
                        js.append("}catch(e){console.log(e)}\n");
                    }
                }
            }
            toStream(request,response,"application/javascript",js.toString());
        }
        @Deprecated
        @GetMapping("/iframe/user-components.js")
        public void iframeJs(HttpServletRequest request,HttpServletResponse response) throws IOException {
            List<MagicalUserComponent> components = magicalUserComponentService.allDistinctComponents();
            StringBuilder js = new StringBuilder();
            if(ListUtil.isNotBlank(components)){
                for(MagicalUserComponent component:components){
                    if(StringUtil.isNotBlank(component.getIframeJs())){
                        js.append("try{\n");
                        js.append(component.getIframeJs()).append("\n");
                        js.append("}catch(e){console.log(e)}\n");
                    }
                }
            }
            toStream(request,response,"application/javascript",js.toString());
        }
        @Deprecated
        @GetMapping("/iframe/user-components.css")
        public void iframeCss(HttpServletRequest request,HttpServletResponse response) throws IOException {
            List<MagicalUserComponent> components = magicalUserComponentService.allDistinctComponents();
            StringBuilder css = new StringBuilder();
            if(ListUtil.isNotBlank(components)){
                for(MagicalUserComponent component:components){
                    if(StringUtil.isNotBlank(component.getIframeCss())){
                        css.append(component.getIframeCss()).append("\n");
                    }
                }
            }
            toStream(request,response,"text/css",css.toString());
        }
        private void toStream(HttpServletRequest request,HttpServletResponse response,String contentType,String text) throws IOException {
            String hashcode = Math.abs(text.hashCode())+"";
            Date now = new Date();
            boolean is304 = false;
            if(!httpCacheMap.containsKey(hashcode)){//唯一一个可能内存泄漏点 但是项目不多 改动不多问题不大 一旦重启就清空了
                McHttpCache cache = new McHttpCache();
                cache.setDate(now);
                httpCacheMap.put(hashcode,cache);
            }else {
                is304 = true;
            }
            McHttpCache cache = httpCacheMap.get(hashcode);

            String encode = "UTF-8";
            response.setCharacterEncoding(encode);
            response.setContentType(contentType+";charset=" + encode);
//            response.setHeader("Etag",hashcode);
//            response.setHeader("Date",now.toString());
            response.setHeader("Last-Modified",cache.getDate().toString());
//            response.setHeader("Date","Tue, 07 Dec 2021 09:09:19 GMT");
//            response.setHeader("Last-Modified","Fri, 12 Nov 2021 01:34:18 GMT");
            response.setHeader("Accept-Ranges","bytes");
//            response.setHeader("Cache-control","max-age=30000000,no-cache");
//            response.setHeader("Expires","Tue Dec 08 16:35:14 CST 2021");
            byte[] bytes = text.getBytes(StandardCharsets.UTF_8);

            if(StringUtil.isNotBlank(request.getHeader("if-modified-since"))){
                if(is304){//让浏览器使用本地缓存
                    response.setStatus(304);
                    response.setContentLength(0);
                    OutputStream writer = response.getOutputStream();
                    writer.write(new byte[]{});
                    writer.flush();
                    return;
                }
            }
            response.setContentLength(bytes.length);
            response.setStatus(200);
            OutputStream writer = response.getOutputStream();
            writer.write(bytes);
            writer.flush();
        }



}
